#include "rpcprovider.h"
#include "rpcheader.pb.h"

void RpcProvider::NotifyService(google::protobuf::Service *service)
{
    ServiceInfo service_info;

    //获取了服务对象的描述信息
    const google::protobuf::ServiceDescriptor *pdesc = service->GetDescriptor();
    //获取服务的名字
    std::string service_name = pdesc->name();
    //获取服务对象方法数量
    int methodCnt= pdesc->method_count();
    
    std::cout<<"service_name:"<<service_name<<std::endl;

    for(int i = 0; i < methodCnt; i++)
    {
        const google::protobuf::MethodDescriptor *pmethodDesc = pdesc->method(i);
        std::string method_name = pmethodDesc ->name();
        service_info.m_methodMap.insert({method_name, pmethodDesc});
        
        std::cout<<"method_name:"<<method_name<<std::endl;
    }
    service_info.m_service = service;
    m_serviceMap.insert({service_name, service_info});
}

void RpcProvider::Run()
{
    std::string ip = MprpcApplication::GetInstance().GetConfig().Load("rpcserverip");
    uint16_t port = atoi(MprpcApplication::GetInstance().GetConfig().Load("rpcserverport").c_str());
    muduo::net::InetAddress address(ip,port);
    
    //创建server对象
    muduo::net::TcpServer server(&m_eventLoop,address,"RpcProvider");
    //绑定连接回调和消息读写回调方法，以及设置合适的loop线程数量

    server.setConnectionCallback(std::bind(&RpcProvider::OnConnection,this,std::placeholders::_1));
    server.setMessageCallback(std::bind(&RpcProvider::OnMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

    server.setThreadNum(4);
    std::cout<<"RpcProvider start service at ip:"<<ip<<" port:"<<port<<std::endl;

    //启动网络服务
    server.start();
    m_eventLoop.loop();
}

//连接回调
void RpcProvider::OnConnection(const muduo::net::TcpConnectionPtr &conn)
{
    if (!conn->connected())
    {
        conn->shutdown();
    }
}

/*
    框架内部 Provider和Consumer协商号通信用的protobuf数据类型
    header_size(4个字节) + header_str + args_str
    */
//已连接用户回调
void RpcProvider::OnMessage(const muduo::net::TcpConnectionPtr &conn, muduo::net::Buffer *buffer, muduo::Timestamp time)
{
    //网络几首到远程rpc调用请求的字符流
    std::string recv_buf = buffer->retrieveAllAsString();
    
    //从字符流中读取前4个字节的内容 字符串数字长度不固定 但是int固定
    uint32_t header_size = 0;
    recv_buf.copy((char *)&header_size, 4, 0);
    std::string rpc_header_str = recv_buf.substr(4, header_size);
    
    //反序列化rpc请求数据
    std::string service_name;
    std::string method_name;
    uint32_t args_size;

    mprpc::RpcHeader rpc_header;
    if (rpc_header.ParseFromString(rpc_header_str))
    {
        service_name = rpc_header.service_name();
        method_name = rpc_header.method_name();
        args_size = rpc_header.args_size();
    }
    else{
        std::cout<<"rpc_header parse error!"<<std::endl;
        return;
    }

    std::string args_str = recv_buf.substr(4 + header_size, args_size);

    //打印调试信息
    std::cout<<"=========================================="<<std::endl;
    std::cout<<"header_size:"<<header_size<<std::endl;
    std::cout<<"rpc_header_str:"<<rpc_header_str<<std::endl;
    std::cout<<"service_name:"<<service_name<<std::endl;
    std::cout<<"method_name:"<<method_name<<std::endl;
    std::cout << "args_str:" << args_str << std::endl;
    std::cout << "==========================================" << std::endl;

    //获取service对象和method对象
    auto it = m_serviceMap.find(service_name);
    if (it == m_serviceMap.end())
    {
        std::cout << service_name << " is not exist!" << std::endl;
        return;
    }

    

    auto mit = it->second.m_methodMap.find(method_name);
    if (mit == it->second.m_methodMap.end())
    {
        std::cout << method_name << " is not exist!" << std::endl;
        return;
    }

    google::protobuf::Service *service = it->second.m_service;//获取service对象
    const google::protobuf::MethodDescriptor *method = mit->second;//获取method对象

    //生成rpc方法调用的请求request和响应response参数
    google::protobuf::Message *request = service->GetRequestPrototype(method).New();
    if(!request->ParseFromString(args_str))
    {
        std::cout<<"request parse error, content:"<<args_str<<std::endl;
        return;
    }
    google::protobuf::Message *response = service->GetResponsePrototype(method).New();
    
    //给下面的method方法的调用绑定一个Closure的回调函数
    google::protobuf::Closure *done = google::protobuf::NewCallback<RpcProvider, const muduo::net::TcpConnectionPtr &, google::protobuf::Message *>(this, &RpcProvider::SendRpcResponse, conn, response);

    //在框架上根据远端rpc请求，调用当前rpc节点上发布的方法
    service->CallMethod(method, nullptr, request, response, done);
}

void RpcProvider::SendRpcResponse(const muduo::net::TcpConnectionPtr &conn, google::protobuf::Message *response)
{
    std::string response_str;
    if (response->SerializeToString(&response_str))
    {
        //序列化成功 通过网络把rpc方法执行结果发送回rpc的调用方
        conn->send(response_str);
    }
    else
    {
        std::cout<<"serialize response_str error!"<<std::endl;
    }
    conn->shutdown();//模拟http的短链接服务，由rpcprovider主动断开连接
}